package com.ccrfid.rmc6.service.business.entrance;

import com.ccrfid.rmc6.entity.business.entrance.PersonnelEntranceRecordEntity;
import com.ccrfid.rmc6.entity.device.LocatorEntity;
import com.ccrfid.rmc6.entity.personnel.PersonnelEntity;
import com.ccrfid.rmc6.entity.personnel.PersonnelMoveEntity;
import com.ccrfid.rmc6.entity.poi.PoiLocationEntity;
import com.ccrfid.rmc6.pojo.Constants;
import com.ccrfid.rmc6.pojo.dto.HardWorkingInfoDto;
import com.ccrfid.rmc6.pojo.dto.TimeRecord;
import com.ccrfid.rmc6.repository.business.entrance.PersonnelEntranceRecordRepository;
import com.ccrfid.rmc6.repository.device.LocatorRepository;
import com.ccrfid.rmc6.repository.personnel.PersonnelMoveRepository;
import com.ccrfid.rmc6.repository.personnel.PersonnelRepository;
import com.ccrfid.rmc6.repository.poi.PoiLocationRepository;
import com.ccrfid.rmc6.service.sys.DictService;
import com.ccrfid.rmc6.util.DateUtil;
import com.ccrfid.rmc6.util.GeomUtil;
import com.vividsolutions.jts.geom.Point;
import org.hibernate.query.NativeQuery;
import org.hibernate.transform.Transformers;
import org.hibernate.type.LongType;
import org.hibernate.type.StringType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.transaction.Transactional;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
@Transactional
public class PersonnelEntranceServiceImpl implements PersonnelEntranceService {
    private static final Logger logger = LoggerFactory.getLogger(PersonnelEntranceServiceImpl.class);
    @PersistenceContext
    private EntityManager entityManager;
    @Autowired
    private DictService dictService;
    @Autowired
    private PersonnelRepository personnelRepository;
    @Autowired
    private PersonnelMoveRepository personnelMoveRepository;
    @Autowired
    private PersonnelEntranceRecordRepository personnelEntranceRecordRepository;
    @Autowired
    private LocatorRepository locatorRepository;
    @Autowired
    private PoiLocationRepository poiLocationRepository;

    @Value("${entrance.locators}")
    private List<Integer> entranceLocators;

    private List<PoiLocationEntity> entranceLocations;

    @PostConstruct
    private void init() {
        entranceLocations = getEntranceLocations();
        logger.debug("entranceLocators: {}, entranceLocations: {}", entranceLocators, entranceLocations);
    }

    private List<PoiLocationEntity> getEntranceLocations() {
        List<PoiLocationEntity> list = new ArrayList<>();
        if (entranceLocators != null && entranceLocators.size() > 0) {
            for (Integer locatorAddress : entranceLocators) {
                LocatorEntity locatorEntity = locatorRepository.getByLocatorAddress(locatorAddress);
                if (locatorEntity != null && locatorEntity.getFloorNumber() != null && locatorEntity.getPos() != null) {
                    PoiLocationEntity poiLocationEntity = poiLocationRepository.get3LevelLocationContainsPoint(
                            locatorEntity.getFloorNumber(), locatorEntity.getPos());
                    if (poiLocationEntity != null) {
                        list.add(poiLocationEntity);
                    }
                }
            }
        }
        return list;
    }

    @Override
    @Scheduled(cron = "0 0 2 * * ?")
    //Scheduled(cron = "秒 分 时 日 月 星期")
    //定时任务，每天凌晨2点钟执行一次
    public void scheduleTask() {
        doTask();
        logger.debug("do scheduleTask(entrance-exit) finish.");
    }

    private void doTask() {
        Date yesterday = DateUtil.getOneDayBefore(new Date());
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        String dateStr = dateFormat.format(yesterday);
        Date startTime = DateUtil.parseDateTimeStr(dateStr + " 00:00:01");
        Date stopTime = DateUtil.parseDateTimeStr(dateStr + " 23:59:59");

        generateEntranceRecord(startTime, stopTime);
    }

    private void generateEntranceRecord(Date startTime, Date stopTime) {
        List<Integer> typeList = dictService.getDictAndSubDictIdListById(Constants.PERSONNEL_TYPE.WORKER.id);
        List<PersonnelEntity> personnelList = personnelRepository.getAllByEnabledAndPersonnelTypeIn(1, typeList);
        for (PersonnelEntity personnelEntity : personnelList) {
            generatePersonnelEntranceRecord(personnelEntity.getId(), startTime, stopTime);
        }
    }

    private void generatePersonnelEntranceRecord(Long personnelId, Date startTime, Date stopTime) {
        List<PersonnelMoveEntity> moveList =
                personnelMoveRepository.getAllByPersonnelIdAndRecordTimeBetween(personnelId, startTime, stopTime);
        if (moveList != null && moveList.size() > 0) {
            List<TimeRecord> list = new ArrayList<>();
            for (PersonnelMoveEntity moveEntity : moveList) {
                Point frontPos = GeomUtil.INSTANCE.createPoint(moveEntity.getFrontX(), moveEntity.getFrontY());
                Point currentPos = GeomUtil.INSTANCE.createPoint(moveEntity.getCurrentX(), moveEntity.getCurrentY());
                if (moveEntity.getFrontX() != null
                        && inEntranceLocation(moveEntity.getFrontFloorNumber(), frontPos)
                        && moveEntity.getCurrentX() != null
                        && !inEntranceLocation(moveEntity.getCurrentFloorNumber(), currentPos)) {
                    list.add(new TimeRecord(moveEntity.getRecordTime(), null));
                } else if (moveEntity.getFrontX() != null
                        && !inEntranceLocation(moveEntity.getFrontFloorNumber(), frontPos)
                        && moveEntity.getCurrentX() != null
                        && !inEntranceLocation(moveEntity.getCurrentFloorNumber(), currentPos)) {
                    if (list.size() > 0) {
                        TimeRecord timeRecord = list.get(list.size() - 1);
                        timeRecord.setStopTime(moveEntity.getRecordTime());
                    } else {
                        list.add(new TimeRecord(new Timestamp(startTime.getTime()), moveEntity.getRecordTime()));
                    }
                } else if (moveEntity.getFrontX() != null
                        && !inEntranceLocation(moveEntity.getFrontFloorNumber(), frontPos)
                        && moveEntity.getCurrentX() != null
                        && inEntranceLocation(moveEntity.getCurrentFloorNumber(), currentPos)) {
                    if (list.size() > 0) {
                        TimeRecord timeRecord = list.get(list.size() - 1);
                        timeRecord.setStopTime(moveEntity.getRecordTime());
                    }
                }
            }
            if (list.size() > 0) {
                TimeRecord timeRecord = list.get(list.size() - 1);
                if (timeRecord.getStopTime() == null) {
                    timeRecord.setStopTime(new Timestamp(stopTime.getTime()));
                }
            }
            //保存某个警员的进监区记录
            PersonnelEntity personnelEntity = personnelRepository.getById(personnelId);
            for (TimeRecord timeRecord : list) {
                PersonnelEntranceRecordEntity recordEntity = new PersonnelEntranceRecordEntity();
                recordEntity.setPersonnelId(personnelEntity.getId());
                recordEntity.setPersonnelName(personnelEntity.getPersonnelName());
                recordEntity.setEnterTime(timeRecord.getStartTime());
                recordEntity.setLeaveTime(timeRecord.getStopTime());
                recordEntity.setStayTime(timeRecord.getSeconds());
                personnelEntranceRecordRepository.save(recordEntity);
            }
        }
    }

    private boolean inEntranceLocation(Integer floorNumber, Point pos) {
        if (pos == null) {
            return false;
        }
        for (PoiLocationEntity locationEntity : entranceLocations) {
            if (locationEntity.getFloorNumber().equals(floorNumber)
                    && locationEntity.getLocationPolygon().contains(pos)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public List<HardWorkingInfoDto> getPersonnelHardWorkingList(String startDate, String stopDate) {
        String startTime = startDate + " 00:00:00";
        String stopTime = stopDate + " 23:59:59";
        String sql = "select personnel_id as personnelId, personnel_name as personnelName, sum(stay_time) as workTime " +
                " from (select * from personnel_entrance_record where enter_time between '" + startTime + "' and '" + stopTime + "') t" +
                " group by personnel_id, personnel_name order by workTime desc limit 10";
        List<HardWorkingInfoDto> list = entityManager.createNativeQuery(sql)
                .unwrap(NativeQuery.class)
                .addScalar("personnelId", LongType.INSTANCE)
                .addScalar("personnelName", StringType.INSTANCE)
                .addScalar("workTime", LongType.INSTANCE)
                .setResultTransformer(Transformers.aliasToBean(HardWorkingInfoDto.class))
                .list();
        return list;
    }

    @Override
    public void updatePersonnelEntranceRecords(String dateStr) {
        Date startTime = DateUtil.parseDateTimeStr(dateStr + " 00:00:00");
        Date stopTime = DateUtil.parseDateTimeStr(dateStr + " 23:59:59");
        //delete
        personnelEntranceRecordRepository.deleteByEnterTimeBetween(startTime, stopTime);
        //generate
        generateEntranceRecord(startTime, stopTime);
    }
}
